package mongox

import (
	"context"
	"gitee.com/zhongguo168a/go-nodex/dbx"
	"gitee.com/zhongguo168a/gocodes/datax"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
	"go.mongodb.org/mongo-driver/mongo"
)

func NewRequestByName(tableName string) (obj *Request) {
	obj = &Request{}
	obj.tableName = tableName
	return
}

func NewRequest(table *Table) (obj *Request) {
	obj = &Request{}
	obj.table = table
	return
}

type Request struct {
	tableName string
	table     *Table
	db        *Database

	ctx context.Context
	col *mongo.Collection

	dbsubkey    string
	tablesubkey string

	itemHandler func(object interface{}, item map[string]interface{}) (interface{}, error)
	itemCreator func() interface{}
}

func (req *Request) WithContext(ctx context.Context) *Request {
	req.ctx = ctx
	return req
}

func (req *Request) SetDBSubkey(val string) *Request {
	req.dbsubkey = val
	return req
}

func (req *Request) SetDBTableSubkey(val string) *Request {
	req.tablesubkey = val
	return req
}

func (req *Request) getContext() context.Context {
	if req.ctx != nil {
		return req.ctx
	}

	return context.Background()
}
func (req *Request) getLastDatabaseName() (name string) {
	return req.db.getLastName()
}

func (req *Request) getLastTableName() (name string) {
	return req.table.GetSubName(req.tablesubkey)
}

func (req *Request) getDatabase() (*Database, error) {
	if req.db == nil {
		table, err := req.getTable()
		if err != nil {
			return nil, errorx.Wrap(err, "get table", datax.M{"table": table.Name})
		}

		db, err := getDatabase(table.Database)
		if err != nil {
			return nil, err
		}
		req.db = db
	}
	return req.db, nil
}

func (req *Request) getTable() (*Table, error) {
	if req.table == nil {
		table, err := getTable(req.tableName)
		if err != nil {
			return nil, err
		}
		req.table = table
	}

	return req.table, nil
}

func (req *Request) GetCollection() (*mongo.Collection, error) {
	if req.col == nil {
		db, err := req.getDatabase()
		if err != nil {
			return nil, err
		}

		addr, err := db.GetAddr(req.dbsubkey)
		if err != nil {
			return nil, errorx.Wrap(err, "get db addr", datax.M{"subkey": req.dbsubkey})
		}

		client, err := addr.GetConnection()
		if err != nil {
			return nil, errorx.Wrap(err, "get connection", datax.M{"table": req.table.Name})
		}

		_, err = req.getTable()
		if err != nil {
			return nil, errorx.Wrap(err, "get table", datax.M{"table": req.table.Name})
		}

		req.col = client.Database(req.getLastDatabaseName()).Collection(req.getLastTableName())
	}

	return req.col, nil

}

func getDatabase(name string) (*Database, error) {
	idb, ok := dbx.GetDB(name)
	if ok == false {
		return nil, errorx.New("database not found", datax.M{"database": name})
	}
	db, ok := idb.(*Database)
	if ok == false {
		return nil, errorx.New("not mgo.Database", datax.M{"database": name})
	}
	return db, nil
}

func getTable(name string) (*Table, error) {
	itable, ok := dbx.GetTable(name)
	if ok == false {
		return nil, errorx.New("table not found", datax.M{"tableName": name})
	}
	table, is := itable.(*Table)
	if is == false {
		return nil, errorx.New("not mongox.Table", datax.M{"tableName": name})
	}

	return table, nil
}
